#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
流式ASR WebSocket事件处理器
处理语音识别相关的WebSocket事件
"""

import asyncio
import base64
import threading
import time
from flask import request
from flask_socketio import emit
from core import extensions
from services.streaming_asr_service import StreamingASRService
from socket_events.tts_events import auto_speak_result


def register_asr_events(socketio):
    """
    注册流式ASR相关事件
    
    Args:
        socketio: SocketIO实例
    """
    
    @socketio.on('start_streaming_asr')
    def handle_start_streaming_asr(data=None):
        """开始流式ASR识别"""
        client_id = request.sid
        print(f"🎤 客户端 {client_id} 请求开始流式ASR")
        
        try:
            # 如果已有会话，先清理
            if client_id in extensions.streaming_sessions:
                print(f"⚠️ 客户端 {client_id} 已有流式ASR会话，先清理")
                handle_stop_streaming_asr()
            
            # 创建新的事件循环（在单独的线程中）
            def run_asr_loop(client_id):
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)
                
                # 添加去重缓存
                last_sent_text = {'text': '', 'is_final': False}
                last_executed_command = {'text': '', 'timestamp': 0}  # 防止命令重复执行
                
                # 定义回调函数
                def on_result_callback(result):
                    """中间结果回调"""
                    try:
                        if result and 'text' in result and result['text']:
                            text = result['text']
                            is_final = result.get('is_final', False)
                            
                            # 去重：如果文本和状态都相同，跳过
                            if text == last_sent_text['text'] and is_final == last_sent_text['is_final']:
                                print(f"⚠️ [去重] 跳过重复消息: {text[:30]}...")
                                return
                            
                            # 更新缓存
                            last_sent_text['text'] = text
                            last_sent_text['is_final'] = is_final
                            
                            print(f"📝 [回调触发] 流式ASR结果: {text[:50]}..., is_final={is_final}")
                            
                            # 根据is_final选择事件类型
                            event_name = 'streaming_asr_final' if is_final else 'streaming_asr_partial'
                            
                            # 发送到前端
                            socketio.emit(event_name, {
                                'type': 'final' if is_final else 'partial',
                                'text': text,
                                'is_final': is_final,
                                'timestamp': int(time.time() * 1000)
                            }, room=client_id)
                            
                            print(f"✅ 已发送 {event_name} 事件到客户端 {client_id}")
                            
                    except Exception as e:
                        print(f"❌ 发送识别结果失败: {e}")
                        import traceback
                        traceback.print_exc()
                
                def on_final_callback(result):
                    """最终结果回调 - 处理并执行命令"""
                    try:
                        if result and 'text' in result and result['text']:
                            text = result['text']
                            current_time = time.time()
                            
                            # 调试信息
                            print(f"🔍 [命令去重检查] 当前命令: '{text[:50]}', 上次命令: '{last_executed_command['text'][:50] if last_executed_command['text'] else '(无)'}', 时间差: {current_time - last_executed_command['timestamp']:.2f}秒")
                            
                            # 去重检查：如果是相同的命令且在10秒内，跳过
                            if (text == last_executed_command['text'] and 
                                current_time - last_executed_command['timestamp'] < 10):
                                print(f"⚠️ [命令去重] 跳过重复命令: {text[:50]} (距上次执行 {current_time - last_executed_command['timestamp']:.1f}秒)")
                                return
                            
                            print(f"✅ [命令去重] 允许执行新命令: {text[:50]}")
                            
                            # ⚠️ 重要：先更新执行记录，防止并发执行
                            last_executed_command['text'] = text
                            last_executed_command['timestamp'] = current_time
                            
                            print(f"✅ [最终回调] 流式ASR最终结果: {text}")
                            
                            # 发送最终识别结果到前端
                            socketio.emit('streaming_asr_final', {
                                'type': 'final',
                                'text': text,
                                'timestamp': int(time.time() * 1000)
                            }, room=client_id)
                            print(f"✅ 已发送 streaming_asr_final 事件到客户端 {client_id}")
                            
                            # 🆕 步骤1：意图分类
                            intent_type = extensions.intent_classifier.classify(text)
                            
                            # 根据意图类型选择处理路径
                            if intent_type == 'command':
                                # 走指令执行流程
                                _handle_command_intent(client_id, text, socketio)
                            elif intent_type == 'conversation':
                                # 走对话流程
                                _handle_conversation_intent(client_id, text, socketio)
                        
                    except Exception as e:
                        print(f"❌ 最终回调处理失败: {e}")
                        import traceback
                        traceback.print_exc()
                
                def on_error_callback(error):
                    """错误回调"""
                    try:
                        print(f"❌ 流式ASR错误: {error}")
                        socketio.emit('streaming_asr_error', {
                            'type': 'error',
                            'message': str(error),
                            'timestamp': int(time.time() * 1000)
                        }, room=client_id)
                        
                        # 🔧 如果是会话失效错误，立即清理后端session
                        if "会话已失效" in str(error) or "Timeout waiting" in str(error):
                            print(f"🧹 检测到会话失效，清理客户端 {client_id} 的后端session")
                            # 从会话字典中移除
                            if client_id in extensions.streaming_sessions:
                                del extensions.streaming_sessions[client_id]
                                print(f"✅ 已清理 streaming_sessions[{client_id}]")
                            if client_id in extensions.streaming_audio_queues:
                                del extensions.streaming_audio_queues[client_id]
                                print(f"✅ 已清理 streaming_audio_queues[{client_id}]")
                            if client_id in extensions.streaming_audio_buffer:
                                del extensions.streaming_audio_buffer[client_id]
                                print(f"✅ 已清理 streaming_audio_buffer[{client_id}]")
                            
                            # 通知前端ASR已停止，前端可以重新启动
                            socketio.emit('streaming_asr_stopped', {
                                'type': 'stopped',
                                'reason': 'session_expired',
                                'message': '会话已失效并清理，可以重新启动',
                                'timestamp': int(time.time() * 1000)
                            }, room=client_id)
                            print(f"📤 已发送 streaming_asr_stopped 事件到客户端 {client_id}")
                            
                    except Exception as e:
                        print(f"❌ 发送错误消息失败: {e}")
                        import traceback
                        traceback.print_exc()
                
                try:
                    # 创建StreamingASRService实例
                    asr_service = StreamingASRService(
                        on_result=on_result_callback,
                        on_final=on_final_callback,
                        on_error=on_error_callback
                    )
                    
                    # 创建音频数据队列
                    audio_queue = asyncio.Queue()
                    extensions.streaming_audio_queues[client_id] = audio_queue
                    
                    # 保存会话信息
                    extensions.streaming_sessions[client_id] = {
                        'asr_service': asr_service,
                        'loop': loop,
                        'audio_queue': audio_queue
                    }
                    
                    # 音频发送协程
                    async def audio_sender():
                        """从队列中取出音频数据并发送到ASR服务"""
                        audio_count = 0
                        try:
                            print(f"🎵 客户端 {client_id} 音频发送协程已启动")
                            while client_id in extensions.streaming_sessions:
                                try:
                                    # 从队列中获取音频数据，超时0.1秒
                                    audio_data = await asyncio.wait_for(audio_queue.get(), timeout=0.1)
                                    if audio_data is None:  # 停止信号
                                        print(f"🛑 客户端 {client_id} 收到停止信号")
                                        break
                                    
                                    # 发送音频数据
                                    is_last = audio_data.get('is_last', False)
                                    data = audio_data.get('data', b'')
                                    
                                    if data or is_last:
                                        audio_count += 1
                                        if audio_count % 10 == 0:
                                            print(f"🔊 客户端 {client_id} 已发送 {audio_count} 个音频包到ASR, 大小: {len(data)} 字节")
                                        
                                        await asr_service.send_audio(data, is_last=is_last)
                                        
                                except asyncio.TimeoutError:
                                    # 队列为空，继续等待
                                    continue
                                except Exception as e:
                                    print(f"❌ 客户端 {client_id} 发送音频异常: {e}")
                                    import traceback
                                    traceback.print_exc()
                                    continue
                        except Exception as e:
                            print(f"❌ 客户端 {client_id} 音频发送协程异常: {e}")
                            import traceback
                            traceback.print_exc()
                    
                    # 连接到ASR服务
                    async def connect_and_wait():
                        success = await asr_service.connect()
                        if success:
                            print(f"✅ 客户端 {client_id} 流式ASR连接成功")
                            socketio.emit('streaming_asr_ready', {
                                'type': 'ready',
                                'message': '流式识别已就绪',
                                'timestamp': int(time.time() * 1000)
                            }, room=client_id)
                            
                            # 启动音频发送协程
                            sender_task = asyncio.create_task(audio_sender())
                            
                            # 启动结果接收协程
                            receiver_task = asyncio.create_task(asr_service.receive_results())
                            print(f"🎧 客户端 {client_id} 结果接收协程已启动")
                            
                            # 保持连接，等待音频数据
                            while client_id in extensions.streaming_sessions:
                                await asyncio.sleep(0.1)
                            
                            # 取消所有任务
                            sender_task.cancel()
                            receiver_task.cancel()
                            try:
                                await sender_task
                            except asyncio.CancelledError:
                                pass
                            try:
                                await receiver_task
                            except asyncio.CancelledError:
                                pass
                        else:
                            print(f"❌ 客户端 {client_id} 流式ASR连接失败")
                            socketio.emit('streaming_asr_error', {
                                'type': 'error',
                                'message': '无法连接到ASR服务',
                                'timestamp': int(time.time() * 1000)
                            }, room=client_id)
                    
                    loop.run_until_complete(connect_and_wait())
                    
                except Exception as e:
                    print(f"❌ 流式ASR线程异常: {e}")
                    socketio.emit('streaming_asr_error', {
                        'type': 'error',
                        'message': str(e),
                        'timestamp': int(time.time() * 1000)
                    }, room=client_id)
                finally:
                    loop.close()
            
            # 在新线程中启动ASR循环
            asr_thread = threading.Thread(target=run_asr_loop, args=(client_id,), daemon=True)
            asr_thread.start()
            
            # 初始化音频缓冲区
            extensions.streaming_audio_buffer[client_id] = []
            
            emit('streaming_asr_started', {
                'type': 'started',
                'message': '流式识别已启动',
                'timestamp': int(time.time() * 1000)
            })
            
        except Exception as e:
            print(f"❌ 启动流式ASR失败: {e}")
            emit('streaming_asr_error', {
                'type': 'error',
                'message': f'启动失败: {str(e)}',
                'timestamp': int(time.time() * 1000)
            })
    
    @socketio.on('streaming_audio_chunk')
    def handle_streaming_audio_chunk(data):
        """接收流式音频块"""
        client_id = request.sid
        
        try:
            if client_id not in extensions.streaming_sessions:
                print(f"⚠️ 客户端 {client_id} 没有活跃的流式ASR会话")
                return
            
            session = extensions.streaming_sessions[client_id]
            asr_service = session.get('asr_service')
            loop = session.get('loop')
            
            if not asr_service or not loop:
                print(f"⚠️ 客户端 {client_id} ASR服务或事件循环不可用")
                return
            
            # 解析音频数据（假设前端发送base64编码的数据）
            try:
                if isinstance(data, dict) and 'audio' in data:
                    audio_base64 = data['audio']
                    audio_bytes = base64.b64decode(audio_base64)
                elif isinstance(data, str):
                    audio_bytes = base64.b64decode(data)
                elif isinstance(data, bytes):
                    audio_bytes = data
                else:
                    print(f"⚠️ 未知的音频数据格式: {type(data)}")
                    return
            except Exception as e:
                print(f"❌ 音频数据解码失败: {e}")
                return
            
            # 前端现在直接发送PCM数据（16kHz, 16bit, 单声道）
            # 不需要格式转换，直接使用
            pcm_data = audio_bytes
            
            # 可选：打印每50个包的信息（避免日志过多）
            if not hasattr(handle_streaming_audio_chunk, 'counter'):
                handle_streaming_audio_chunk.counter = 0
            handle_streaming_audio_chunk.counter += 1
            if handle_streaming_audio_chunk.counter % 50 == 0:
                print(f"📦 已接收 {handle_streaming_audio_chunk.counter} 个音频包")
            
            if pcm_data:
                # 将音频数据放入队列，而不是直接发送
                # 这样可以避免并发问题
                audio_queue = session.get('audio_queue')
                if audio_queue:
                    try:
                        # 使用 run_coroutine_threadsafe 将数据放入队列
                        future = asyncio.run_coroutine_threadsafe(
                            audio_queue.put({'data': pcm_data, 'is_last': False}),
                            loop
                        )
                        # 等待入队完成（带超时）
                        future.result(timeout=0.5)
                        
                    except TimeoutError:
                        # 超时错误，可能是客户端已断开，静默处理
                        if client_id in extensions.streaming_sessions:
                            print(f"⚠️ 客户端 {client_id} 音频数据入队超时")
                    except Exception as e:
                        # 其他错误才打印详细信息
                        if client_id in extensions.streaming_sessions:
                            print(f"❌ 客户端 {client_id} 音频数据入队失败: {e}")
                else:
                    print(f"⚠️ 客户端 {client_id} 音频队列不存在")
            
        except Exception as e:
            print(f"❌ 处理音频块失败: {e}")
            import traceback
            traceback.print_exc()
    
    @socketio.on('stop_streaming_asr')
    def handle_stop_streaming_asr(data=None):
        """停止流式ASR识别"""
        client_id = request.sid
        print(f"🛑 客户端 {client_id} 请求停止流式ASR")
        
        try:
            if client_id in extensions.streaming_sessions:
                session = extensions.streaming_sessions[client_id]
                asr_service = session.get('asr_service')
                loop = session.get('loop')
                audio_queue = session.get('audio_queue')
                
                # 先取消任务，避免继续发送音频
                if 'task' in session and session['task']:
                    try:
                        session['task'].cancel()
                        print(f"   ✅ 已取消音频发送任务")
                    except Exception as cancel_error:
                        print(f"   ⚠️ 取消任务失败: {cancel_error}")
                
                if asr_service and loop and not loop.is_closed():
                    try:
                        # 向队列发送停止信号
                        if audio_queue:
                            asyncio.run_coroutine_threadsafe(
                                audio_queue.put(None),  # None作为停止信号
                                loop
                            ).result(timeout=1.0)
                        
                        # 等待一小段时间让发送任务完成
                        time.sleep(0.2)
                        
                        # 断开ASR连接
                        asyncio.run_coroutine_threadsafe(
                            asr_service.disconnect(),
                            loop
                        ).result(timeout=2.0)
                        
                        print(f"   ✅ ASR连接已断开")
                        
                    except Exception as disconnect_error:
                        print(f"   ⚠️ 断开ASR连接失败: {disconnect_error}")
                
                # 清理会话
                del extensions.streaming_sessions[client_id]
                print(f"✅ 客户端 {client_id} 流式ASR会话已完全清理")
            else:
                print(f"⚠️ 客户端 {client_id} 没有活跃的ASR会话")
            
            # 清理其他资源
            if client_id in extensions.streaming_audio_buffer:
                del extensions.streaming_audio_buffer[client_id]
            
            if client_id in extensions.streaming_audio_queues:
                del extensions.streaming_audio_queues[client_id]
            
            emit('streaming_asr_stopped', {
                'type': 'stopped',
                'message': '流式识别已停止',
                'timestamp': int(time.time() * 1000)
            })
            
        except Exception as e:
            print(f"❌ 停止流式ASR失败: {e}")
            import traceback
            traceback.print_exc()
            
            # 即使出错也要尝试清理资源
            try:
                if client_id in extensions.streaming_sessions:
                    del extensions.streaming_sessions[client_id]
                if client_id in extensions.streaming_audio_buffer:
                    del extensions.streaming_audio_buffer[client_id]
                if client_id in extensions.streaming_audio_queues:
                    del extensions.streaming_audio_queues[client_id]
            except:
                pass
            
            emit('streaming_asr_error', {
                'type': 'error',
                'message': f'停止失败: {str(e)}',
                'timestamp': int(time.time() * 1000)
            })


def _handle_command_intent(client_id, text, socketio):
    """
    处理指令意图
    
    Args:
        client_id: 客户端ID
        text: 识别的文本
        socketio: SocketIO实例
    """
    print(f"🤖 [指令处理] 识别为可执行指令，开始处理...")
    try:
        # 调用智能指令处理服务
        command_result = extensions.command_service.process_command(text)
        
        # 检查命令是否执行成功
        success = command_result.get('success', False)
        message = command_result.get('message', '')
        
        # 如果命令执行成功，直接发送结果
        if success:
            # 优先使用execution_result中的实际消息（用于前端显示和TTS播报）
            execution_result = command_result.get('execution_result', {})
            execution_message = execution_result.get('message') if isinstance(execution_result, dict) else None
            display_message = execution_message or message  # 优先使用具体消息
            
            socketio.emit('command_executed', {
                'type': 'command_result',
                'original_text': text,
                'success': True,
                'message': display_message,
                'command_type': command_result.get('parsed_command', {}).get('type', 'unknown'),
                'result': command_result,
                'timestamp': int(time.time() * 1000)
            }, room=client_id)
            print(f"✅ 命令执行成功: {display_message[:50]}..." if len(display_message) > 50 else f"✅ 命令执行成功: {display_message}")
            
            # 🔊 自动语音播报
            if execution_message:
                tts_text = execution_message
                print(f"🔊 [TTS] 播报执行结果: {tts_text[:50]}...")
            else:
                command_type = command_result.get('parsed_command', {}).get('type', 'unknown')
                command_names = {
                    'music_search': '音乐搜索',
                    'online_search': '网页搜索',
                    'file_create': '文件创建',
                    'file_delete': '文件删除',
                    'file_open': '文件打开',
                    'app_open': '应用打开',
                    'system_control': '系统控制',
                    'unknown': '指令'
                }
                command_name = command_names.get(command_type, '指令')
                tts_text = f"{command_name}指令执行完成，您可以继续和我聊天了"
                print(f"🔊 [TTS] 播报通用消息: {tts_text}")
            
            auto_speak_result(client_id, tts_text, speed_ratio=1.2)
        else:
            # 命令执行失败，流式生成友好的LLM回复
            _stream_llm_error_response(client_id, text, message, socketio)
    
    except Exception as cmd_error:
        print(f"❌ 命令处理失败: {cmd_error}")
        import traceback
        traceback.print_exc()
        _stream_llm_error_response(client_id, text, f"系统处理异常: {str(cmd_error)}", socketio)


def _handle_conversation_intent(client_id, text, socketio):
    """
    处理对话意图
    
    Args:
        client_id: 客户端ID
        text: 识别的文本
        socketio: SocketIO实例
    """
    print(f"💬 [对话处理] 识别为对话，直接流式生成回复...")
    
    # 发送开始流式回复的信号
    socketio.emit('llm_response_start', {
        'type': 'llm_stream_start',
        'original_text': text,
        'timestamp': int(time.time() * 1000)
    }, room=client_id)
    
    accumulated_text = ""
    chunk_count = 0
    
    try:
        # 流式生成对话回复
        for chunk in extensions.llm_client.chat_stream(
            user_input=text,
            system_prompt="你是一个友好的AI助手，请用简洁、自然的方式回答用户的问题。⚠️ 回答要简短精炼，控制在150字以内，适合语音播报。如果用户要求写小说/文章，控制在200字以内。",
            max_tokens=250,
            temperature=0.8
        ):
            accumulated_text += chunk
            chunk_count += 1
            
            # 发送流式片段
            socketio.emit('llm_response_chunk', {
                'type': 'llm_stream_chunk',
                'chunk': chunk,
                'accumulated': accumulated_text,
                'timestamp': int(time.time() * 1000)
            }, room=client_id)
        
        # 发送流式结束信号
        socketio.emit('llm_response_end', {
            'type': 'llm_stream_end',
            'full_text': accumulated_text,
            'original_text': text,
            'timestamp': int(time.time() * 1000)
        }, room=client_id)
        
        print(f"✅ [对话处理] 流式对话完成，共 {chunk_count} 个片段")
        
        # 🔊 自动语音播报对话回复
        if accumulated_text:
            auto_speak_result(client_id, accumulated_text, speed_ratio=1.2)
        
    except Exception as conv_error:
        print(f"❌ [对话处理] 对话生成失败: {conv_error}")
        import traceback
        traceback.print_exc()
        
        # 发送错误回复
        if chunk_count == 0:
            error_message = "抱歉，我现在无法回答您的问题。请稍后再试。"
            socketio.emit('llm_response_chunk', {
                'type': 'llm_stream_chunk',
                'chunk': error_message,
                'accumulated': error_message,
                'timestamp': int(time.time() * 1000)
            }, room=client_id)
        
        socketio.emit('llm_response_end', {
            'type': 'llm_stream_end',
            'full_text': accumulated_text if chunk_count > 0 else error_message,
            'original_text': text,
            'timestamp': int(time.time() * 1000)
        }, room=client_id)


def _stream_llm_error_response(client_id, user_command, error_reason, socketio):
    """
    流式生成友好的错误回复
    
    Args:
        client_id: 客户端ID
        user_command: 用户命令
        error_reason: 错误原因
        socketio: SocketIO实例
    """
    print(f"💬 命令执行失败，开始流式生成友好回复...")
    
    # 先发送开始流式回复的信号
    socketio.emit('llm_response_start', {
        'type': 'llm_stream_start',
        'original_text': user_command,
        'error_message': error_reason,
        'timestamp': int(time.time() * 1000)
    }, room=client_id)
    
    accumulated_text = ""
    chunk_count = 0
    
    try:
        # 流式生成并发送
        for chunk in extensions.llm_client.generate_friendly_error_response_stream(
            user_command=user_command,
            error_reason=error_reason
        ):
            accumulated_text += chunk
            chunk_count += 1
            
            # 发送流式片段
            socketio.emit('llm_response_chunk', {
                'type': 'llm_stream_chunk',
                'chunk': chunk,
                'accumulated': accumulated_text,
                'timestamp': int(time.time() * 1000)
            }, room=client_id)
            
            print(f"📤 [发送 Chunk {chunk_count}] {chunk}")
        
        # 发送流式结束信号
        socketio.emit('llm_response_end', {
            'type': 'llm_stream_end',
            'full_text': accumulated_text,
            'original_text': user_command,
            'success': False,
            'message': error_reason,
            'timestamp': int(time.time() * 1000)
        }, room=client_id)
        
        print(f"✅ 流式友好回复已完成，共发送 {chunk_count} 个片段")
        
        # 🔊 自动语音播报LLM回复
        if accumulated_text:
            auto_speak_result(client_id, accumulated_text, speed_ratio=1.2)
        print(f"📝 完整内容: {accumulated_text}")
        
    except Exception as llm_error:
        print(f"⚠️ 流式生成友好回复失败: {llm_error}")
        
        # 只有在完全没有生成任何内容时，才发送默认错误回复
        if chunk_count == 0:
            print(f"💬 完全没有生成内容，发送默认错误回复")
            default_message = f"抱歉，我无法理解您的指令「{user_command}」。您可以试试说：播放音乐、创建文件等。"
            socketio.emit('llm_response_chunk', {
                'type': 'llm_stream_chunk',
                'chunk': default_message,
                'accumulated': default_message,
                'timestamp': int(time.time() * 1000)
            }, room=client_id)
            socketio.emit('llm_response_end', {
                'type': 'llm_stream_end',
                'full_text': default_message,
                'original_text': user_command,
                'success': False,
                'message': error_reason,
                'timestamp': int(time.time() * 1000)
            }, room=client_id)
        else:
            print(f"💬 已生成 {chunk_count} 个片段，流式中断但不添加默认消息")
            # 发送流式结束信号，使用已生成的内容
            socketio.emit('llm_response_end', {
                'type': 'llm_stream_end',
                'full_text': accumulated_text,
                'original_text': user_command,
                'success': False,
                'message': error_reason,
                'timestamp': int(time.time() * 1000)
            }, room=client_id)

